<?php

namespace Console\Supports;

use App\Components\EventService;
use App\Components\Redis;
use Exception;
use Monolog\Registry as Monolog;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ListenerExecution extends Command
{

    protected static $defaultName = 'queue:work';

    protected function configure()
    {
        $this->setDescription('运行事件监听队列');
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $eventProvider = require ROOT_PATH . 'bootstrap/event.php';

        $context = Redis::queueContext();
        $queue = $context->createQueue(EventService::getEventQueueName());
        $consumer = $context->createConsumer($queue);
        while (true) {
            $message = $consumer->receive();
            $eventMsg = $message->getBody();
            $eventMsg = json_decode($eventMsg, true);
            if ($eventMsg === null || !isset($eventMsg['event']) ||
                !isset($eventMsg['payload']) || !isset($eventMsg['created_at'])
            ) {
                Monolog::getInstance('cmc')->notice('事件监听,消息有问题', [
                    'event' => $message->getBody(),
                ]);
                $consumer->acknowledge($message);
                continue;
            }

            $eventMsg['payload'] = unserialize($eventMsg['payload']);
            if ($eventMsg['payload'] === false) {
                Monolog::getInstance('cmc')->error('事件监听,消息体解析错误', [
                    'event' => $message->getBody(),
                ]);
                $consumer->acknowledge($message);
                continue;
            }

            if (!isset($eventProvider[$eventMsg['event']])) {
                Monolog::getInstance('cmc')->notice('事件监听,事件名称未定义', [
                    'msg' => $eventMsg,
                ]);
                $consumer->acknowledge($message);
                continue;
            }
            $output->write('[' . date('Y-m-d H:i:s') . '][' . $eventMsg['created_at'] . ']');
            $output->write('Processing: ' . $eventMsg['event'] . PHP_EOL);
            foreach ($eventProvider[$eventMsg['event']] as $listener) {
                try {
                    $classMethod = get_class_methods($listener);
                    if (!is_array($classMethod) || !in_array('handle', $classMethod)) {
                        throw new Exception('handle方法不存在');
                    }
                    unset($classMethod);

                    $listenerObject = new $listener;
                    $executeResult = $listenerObject->handle($eventMsg['payload']);
                } catch (Exception $e) {
                    Monolog::getInstance('cmc')->notice('事件监听,监听处理错误', [
                        'msg' => $eventMsg,
                        'listener' => $listener,
                        'error' => $e->getMessage(),
                    ]);

                    $consumer->reject($message, true);
                    break 2;
                }
                $output->write('[' . date('Y-m-d H:i:s') . '][' . $eventMsg['event'] . ']');
                $output->write('Processed: ' . $listener . PHP_EOL);

                if ($executeResult !== true) {
                    break;
                }
            }
            $consumer->acknowledge($message);
        }

        return 0;
    }
}
